﻿// --------------------------------------------------------------------------------------------------------------------
// <copyright file="TransactionFilter.cs" company="Concept Architecture">
//   (c) 2010 Muhammad Umer Farooq
// </copyright>
// <summary>
//   Defines the <seealso cref="Hisaab.Data.Filters.TransactionFilter" /> type.
// </summary>
// --------------------------------------------------------------------------------------------------------------------

namespace Hisaab.Data.Filters
{
    using System;
    using System.Data.Objects;
    using System.Linq;
    using Entities;

    /// <summary>
    /// Defines the <seealso cref="Hisaab.Data.Filters.TransactionFilter"/> type.
    /// </summary>
    public static class TransactionFilter
    {
        /// <summary>
        /// Filters the specified Transaction collection.
        /// </summary>
        /// <param name="collection">The Transaction collection.</param>
        /// <param name="objectToMatch">The Transaction to match.</param>
        /// <returns>List of filtered Transactions</returns>
        public static IQueryable<Transaction> Filter(this IQueryable<Transaction> collection, Transaction objectToMatch)
        {
            return objectToMatch == null ?
                collection :
                from transaction in collection
                where (objectToMatch.Id == 0 || transaction.Id == objectToMatch.Id) &&
                    (objectToMatch.Title == null || transaction.Title.Equals(objectToMatch.Title, StringComparison.InvariantCultureIgnoreCase)) &&
                    (objectToMatch.Details == null || transaction.Details.Equals(objectToMatch.Details, StringComparison.InvariantCultureIgnoreCase)) &&
                    (objectToMatch.Amount == 0 || transaction.Amount == objectToMatch.Amount) &&
                (objectToMatch.Account == 0 || transaction.Account == objectToMatch.Account)
                select transaction;
        }

        /// <summary>
        /// Filters the by tag.
        /// </summary>
        /// <param name="transactions">The collection.</param>
        /// <param name="tagId">The tag id to match.</param>
        /// <returns>List of filtered Transactions</returns>
        public static IQueryable<Transaction> FilterByTag(this IQueryable<Transaction> transactions, int tagId)
        {
            return transactions.Where(x => x.Tags.Any(y => y.Id == tagId));
        }

        /// <summary>
        /// Betweens the dates.
        /// </summary>
        /// <param name="collection">The collection.</param>
        /// <param name="objectToMatch">The object to match.</param>
        /// <param name="startDate">The start date.</param>
        /// <param name="endDate">The end date.</param>
        /// <returns>List of filtered Transactions</returns>
        public static IQueryable<Transaction> BetweenDates(this IQueryable<Transaction> collection, Transaction objectToMatch, DateTime startDate, DateTime endDate)
        {
            return from transaction in Filter(collection, objectToMatch)
                   where transaction.Date >= startDate && transaction.Date <= endDate
                   select transaction;
        }

        /// <summary>
        /// Betweens the dates.
        /// </summary>
        /// <param name="collection">The collection.</param>
        /// <param name="startDate">The start date.</param>
        /// <param name="endDate">The end date.</param>
        /// <returns>List of filtered Transactions</returns>
        public static IQueryable<Transaction> BetweenDates(this IQueryable<Transaction> collection, DateTime startDate, DateTime endDate)
        {
            return from transaction in collection
                   where transaction.Date >= startDate && transaction.Date <= endDate
                   select transaction;
        }

        /// <summary>
        /// Orders the by.
        /// </summary>
        /// <param name="collection">The collection.</param>
        /// <param name="sortBy">The sort by.</param>
        /// <param name="orderBy">The order by.</param>
        /// <returns>Ordered list of transactions</returns>
        public static IOrderedQueryable<Transaction> OrderTransactions(this IQueryable<Transaction> collection, SortByType sortBy, OrderByType orderBy)
        {
            IOrderedQueryable<Transaction> orderedTransactions;
            if (orderBy == OrderByType.Ascending)
            {
                switch (sortBy)
                {
                    case SortByType.Amount:
                        orderedTransactions = collection.OrderBy(x => Math.Abs(x.Amount));
                        break;
                    case SortByType.Type:
                        orderedTransactions = collection.OrderBy(x => OrderByTransactionType(x));
                        break;
                    default:
                        orderedTransactions = collection.OrderBy(x => x.Date);
                        break;
                }
            }
            else
            {
                switch (sortBy)
                {
                    case SortByType.Amount:
                        orderedTransactions = collection.OrderByDescending(x => Math.Abs(x.Amount));
                        break;
                    case SortByType.Type:
                        orderedTransactions = collection.OrderByDescending(x => OrderByTransactionType(x));
                        break;
                    default:
                        orderedTransactions = collection.OrderByDescending(x => x.Date);
                        break;
                }
            }

            return orderedTransactions;
        }

        /// <summary>
        /// Orders the type of the by.
        /// </summary>
        /// <param name="x">The x.</param>
        /// <returns>Transaction type</returns>
        private static string OrderByTransactionType(Transaction x)
        {
            return x.Amount < 0 ? "Expanse" : "Income";
        }
    }
}